#pragma once
#include "thread.hpp"
#include "LockGuard.hpp"
#include "Log.hpp"
#include <queue>
#include <vector>
#include <string>
namespace ThreadNs
{

    class threadData
    {
    public:
        threadData(const std::string &threadName)
            : _threadName(threadName)
        {
        }

        std::string _threadName;
    };

    const int default_threadNum = 5;

    template <class T>
    class ThreadPool
    {
    private:
        ThreadPool(int threadNum = default_threadNum)
            : _threadNum(threadNum)
        {
            pthread_mutex_init(&_mutex, nullptr);
            pthread_cond_init(&_cond, nullptr);

            // 创建线程
            for (int i = 0; i < _threadNum; i++)
            {
                std::string threadname = "thread-";
                threadname += std::to_string(i + 1);

                threadData td(threadname);
                _threads.emplace_back(threadname, std::bind(&ThreadPool<T>::ThreadRun, this, std::placeholders::_1), td);

                lg.LogMessage(Info, "%s is created...", threadname.c_str());
            }
        }

        ThreadPool(const ThreadPool<T> &tp) = delete;
        const ThreadPool<T> &operator=(const ThreadPool<T>) = delete;

    public:
        static ThreadPool<T> *GetInstance()
        {
            if (instance == nullptr)
            {
                LockGuard lock(&_sig_mutex);
                // 创建一个单列
                if (instance == nullptr)
                {
                    lg.LogMessage(Info, "创建一个单例...");
                    instance = new ThreadPool<T>();
                }
            }
            return instance;
        }

        bool Start()
        {
            for (auto &thread : _threads)
            {
                thread.Start();
                lg.LogMessage(Info, "%s is running...", thread.ThreadName().c_str());
            }
            return true;
        }

        void ThreadWait(threadData &td)
        {
            lg.LogMessage(Debug, "no task, %s is sleeping...", td._threadName.c_str());
            pthread_cond_wait(&_cond, &_mutex);
        }

        void ThreadWakeup()
        {
            // 唤醒
            pthread_cond_signal(&_cond);
        }

        void ThreadRun(threadData &td)
        {
            while (true)
            {
                T t;
                {
                    LockGuard loguard(&_mutex);
                    while (_q.empty())
                    {
                        // 等待
                        ThreadWait(td);
                        lg.LogMessage(Debug, "%s is weakup", td._threadName.c_str());
                    }

                    t = _q.front();
                    _q.pop();
                }
                // 处理
                t();
                // lg.LogMessage(Debug, "%s hander task %s,result is: %s\n", td._threadName.c_str(),
                //  t.PrintTask().c_str(), t.PrintResult().c_str());
            }
        }

        void Push(T in)
        {
            // 有数据就唤醒
            LockGuard lockguard(&_mutex);
            // lg.LogMessage(Debug, "other thread push a task, task is : %s\n", in.PrintTask().c_str());
            _q.push(in);

            ThreadWakeup();
        }

        void Wait()
        {
            for (auto &thread : _threads)
            {
                thread.Join();
            }
        }

        ~ThreadPool()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_cond);
        }

    private:
        std::queue<T> _q;
        std::vector<Thread<threadData>> _threads;
        int _threadNum;
        pthread_mutex_t _mutex;
        pthread_cond_t _cond;

        static ThreadPool<T> *instance;
        static pthread_mutex_t _sig_mutex;
    };

    template <class T>
    ThreadPool<T> *ThreadPool<T>::instance = nullptr;
    template <class T>
    pthread_mutex_t ThreadPool<T>::_sig_mutex = PTHREAD_MUTEX_INITIALIZER;
}